package minijvm.cmd;

import minijvm.clz.ClassFile;
import minijvm.engine.ExecutionResult;
import minijvm.engine.Heap;
import minijvm.engine.JavaObject;
import minijvm.engine.StackFrame;

import static minijvm.cmd.CommandParser.*;

/**
 * @author ChangLiang
 * @date 2020/4/26
 */
public class NoOperandCmd extends ByteCodeCommand {


    protected NoOperandCmd(ClassFile clzFile, String opCode) {
        super(clzFile, opCode);
    }

    @Override
    public void execute(StackFrame frame, ExecutionResult result) {
        switch (this.opCode) {
            case dup:{
                JavaObject javaObject = frame.getOperandStack().peek();
                frame.getOperandStack().push(javaObject);
                break;
            }
            case aload_0:{
                JavaObject javaObject = frame.getLocalVariableValue(0);
                frame.getOperandStack().push(javaObject);
                break;
            }
            case aload_1:
            case iload_1:{
                JavaObject javaObject = frame.getLocalVariableValue(1);
                frame.getOperandStack().push(javaObject);
                break;
            }
            case iload_2:
            case aload_2:{
                JavaObject javaObject = frame.getLocalVariableValue(2);
                frame.getOperandStack().push(javaObject);
                break;
            }
            case iload_3:{
                JavaObject javaObject = frame.getLocalVariableValue(3);
                frame.getOperandStack().push(javaObject);
                break;
            }
            case istore_1:
            case astore_1:{
                JavaObject javaObject = frame.getOperandStack().pop();
                frame.setLocalVariableValue(1,javaObject);
                break;
            }
            case astore_2:
            case istore_2:{
                JavaObject javaObject = frame.getOperandStack().pop();
                frame.setLocalVariableValue(2,javaObject);
                break;
            }
            case ireturn:{
                JavaObject javaObject = frame.getOperandStack().pop();
                // 涉及到将值传回到上一个栈帧
                frame.getCallerFrame().getOperandStack().push(javaObject);
                result.setNextAction(ExecutionResult.EXIT_CURRENT_FRAME);
                break;
            }
            case voidreturn:{
                result.setNextAction(ExecutionResult.EXIT_CURRENT_FRAME);
                break;
            }
            case aconst_null:{
                frame.getOperandStack().push(null);
                break;
            }
            case iconst_m1:{
                JavaObject javaObject = Heap.getInstance().newInt(-1);
                frame.getOperandStack().push(javaObject);
                break;
            }
            case iconst_0:{
                JavaObject javaObject = Heap.getInstance().newInt(0);
                frame.getOperandStack().push(javaObject);
                break;
            }
            case iconst_1:{
                JavaObject javaObject = Heap.getInstance().newInt(1);
                frame.getOperandStack().push(javaObject);
                break;
            }
            case iconst_2:{
                JavaObject javaObject = Heap.getInstance().newInt(2);
                frame.getOperandStack().push(javaObject);
                break;
            }
            case iconst_3:{
                JavaObject javaObject = Heap.getInstance().newInt(3);
                frame.getOperandStack().push(javaObject);
                break;
            }
            case iconst_4:{
                JavaObject javaObject = Heap.getInstance().newInt(4);
                frame.getOperandStack().push(javaObject);
                break;
            }
            case iconst_5:{
                JavaObject javaObject = Heap.getInstance().newInt(5);
                frame.getOperandStack().push(javaObject);
                break;
            }
            case iadd:{
                JavaObject intValue1 = frame.getOperandStack().pop();
                JavaObject intValue2 = frame.getOperandStack().pop();
                JavaObject javaObject = Heap.getInstance().newInt(intValue1.getIntValue() + intValue2.getIntValue());
                frame.getOperandStack().push(javaObject);
                break;
            }
            default:{
                throw new RuntimeException("Cmd has not been implement: "+opCode);
            }
        }
    }

    @Override
    public int getLength() {
        return 1;
    }
}
